package test;

import item.Samochod;

import java.util.LinkedList;
import java.util.List;

import Transporter.Transporter;
import kolejka.Kolejka;
import kolejka.KolejkaFIFO;
import stanowisko.Stanowisko;
import stanowisko.StanowiskoConst;
import system.MySystem;
import utils.Logger;
import utils.NetworkLogger;

public class Network {
	private LinkedList<Samochod> listaSamochodowDoPrzybycia;
	private LinkedList<MySystem> listaSystemow = new LinkedList<MySystem>();
	NetworkLogger log = new NetworkLogger(false);
	private double aktualnyCzas = 0;

	public Network() {
		generujSamochodyDoPrzybycia();
		dodajSystemyDoSieci();
	}

	private void generujSamochodyDoPrzybycia() {
		listaSamochodowDoPrzybycia = new LinkedList<Samochod>();
		this.listaSamochodowDoPrzybycia.add(new Samochod(1, 0));
		this.listaSamochodowDoPrzybycia.add(new Samochod(2, 3));
		this.listaSamochodowDoPrzybycia.add(new Samochod(3, 5));
		this.listaSamochodowDoPrzybycia.add(new Samochod(4, 10));
		this.listaSamochodowDoPrzybycia.add(new Samochod(5, 15));
		this.listaSamochodowDoPrzybycia.add(new Samochod(6, 21));
	}

		private void umiescSamochodyWPierwszejKolejce(double aktualnyCzas) {
	
			while (!listaSamochodowDoPrzybycia.isEmpty()
					&& listaSamochodowDoPrzybycia.getFirst().dajCzasPrzybycia() <= aktualnyCzas) {
	
				Samochod dodawanySamochod = listaSamochodowDoPrzybycia.removeFirst();
	
				if (jestMiejsceWSystemie()) {
					listaSystemow.get(0).getKolejka().dodaj(dodawanySamochod);
					// this.liczbaSamochodowObsluzonych++;
					this.log.logAddItemToQueue(dodawanySamochod.dajCzasPrzybycia(), dodawanySamochod, listaSystemow.get(0)
							.getKolejka().dajWszystkie(), listaSystemow.get(0).getId());
				}
				else {
					System.out.println("Brak miejsca w systemie. Samochod: "+dodawanySamochod.dajID()+" opuszcza system");
				}			
			}
		}
	
				private boolean jestMiejsceWSystemie() {
					return this.listaSystemow.get(0).getPojemnoscSystemu() == 0 || (this.listaSystemow.get(0).getKolejka().rozmiar() < this.listaSystemow.get(0).getPojemnoscSystemu() - 1);
				}
	
	/**
	 * 		 		 ____________ 		  ____________
	 *				|			 | 60%  |			  |
	 * GENERATOR--> |D|D|1|FIFO|3|------>|D|D|1|FIFO|2|---->KONIEC
	 * 				|____________|		 |____________|  	  ^
	 *                            \       					  |
	 * 							   \______________0%_________|
	 */
	private void dodajSystemyDoSieci() {
		//system D|D|1|FIFO|3 z czasem obsługi 10s
		Stanowisko<Samochod> myjnia1 = new StanowiskoConst<Samochod>(1, 10);
		LinkedList<Stanowisko<Samochod>> myjnie1 = new LinkedList<Stanowisko<Samochod>>();
		myjnie1.add(myjnia1);
		Kolejka<Samochod> kolejkaSamochodow1 = new KolejkaFIFO<Samochod>(1);
		MySystem s1 = new MySystem(kolejkaSamochodow1, myjnie1, null, 3, 1);

		//system D|D|1|FIFO|2 z czasem obsługi 14s
		Stanowisko<Samochod> myjnia2 = new StanowiskoConst<Samochod>(2, 14);
		LinkedList<Stanowisko<Samochod>> myjnie2 = new LinkedList<Stanowisko<Samochod>>();
		myjnie2.add(myjnia2);
		Kolejka<Samochod> kolejkaSamochodow2 = new KolejkaFIFO<Samochod>(2);
		MySystem s2 = new MySystem(kolejkaSamochodow2, myjnie2, null, 2, 2);
		
		Stanowisko<Samochod> myjnia3 = new StanowiskoConst<Samochod>(3, 14);
		LinkedList<Stanowisko<Samochod>> myjnie3 = new LinkedList<Stanowisko<Samochod>>();
		myjnie3.add(myjnia3);
		Kolejka<Samochod> kolejkaSamochodow3 = new KolejkaFIFO<Samochod>(3);
		MySystem s3 = new MySystem(kolejkaSamochodow3, myjnie3, null, 2, 3);

		LinkedList<MySystem> listaTo = new LinkedList<MySystem>();
		listaTo.add(s2);
		listaTo.add(s3);
		Transporter t12 = new Transporter(s1, listaTo, new int[] { 100, 0 });
		s1.setTransporter(t12);

		this.listaSystemow.add(s1);
		this.listaSystemow.add(s2);
		this.listaSystemow.add(s3);
	}

	public void symulacja() {
//		double lacznyCzasCzekaniaWKolejce = 0;
//		double czasOstatniegoZdarzenia = 0;
//		double aktualnyCzas = 0;

		while (!listaSamochodowDoPrzybycia.isEmpty() || !czySystemyPuste()) {
			umiescSamochodyWPierwszejKolejce(aktualnyCzas);

			for(MySystem system : this.listaSystemow) {
				system.usunElementyKtoreSieDa(aktualnyCzas);
			}
			
			for(MySystem system : this.listaSystemow) {
				system.dodajObiektJesliSieDa(aktualnyCzas);
			}
//			czasOstatniegoZdarzenia = aktualnyCzas;			
			odblokujStanowiskaJesliSieDa();
			
			aktualnyCzas = dajCzasNajblizszegoZdarzenia();
		}
		System.out.println("Koniec symulacji");
		System.out.println("dlugosc kolejki drugiego systemu: "+this.listaSystemow.get(1).getKolejka().rozmiar());
		System.out.println("puste stanowisko: "+this.listaSystemow.get(1).getMyjnie().get(0).czyPusty());
		System.out.println("puste stanowisko: "+this.listaSystemow.get(0).getMyjnie().get(0).czyPusty());
		
	}

		private void odblokujStanowiskaJesliSieDa() {
			for(MySystem system: this.listaSystemow) {
				for(Stanowisko<Samochod> s : system.getMyjnie()) {
					if(s.czyZablokowana()) {
						if(system.getTransporter().isTransportPossible()) {
							s.zablokowana(false);
						}
					}
				}
				
			}
		}
	
	private double dajCzasNajblizszegoZdarzenia() {
		double czasNajblizszegoZdarzenia = Double.MAX_VALUE;

		if (!this.listaSamochodowDoPrzybycia.isEmpty()) {
			czasNajblizszegoZdarzenia = this.listaSamochodowDoPrzybycia.getFirst().dajCzasPrzybycia();
		}

		//bierze czasy z kazdego z systemow
		for (MySystem system : this.listaSystemow) {
			if (system.dajCzasNajblizszegoZdarzenia(aktualnyCzas) < czasNajblizszegoZdarzenia) {
				czasNajblizszegoZdarzenia = system.dajCzasNajblizszegoZdarzenia(aktualnyCzas);
			}
		}
		return czasNajblizszegoZdarzenia;
	}
	
	private boolean czySystemyPuste() {
		for(MySystem system : this.listaSystemow) {
			if(!czySystemPusty(system))
				return false;
		}
		return true;
	}
	
		private boolean czySystemPusty(MySystem system) {
			if(system.getKolejka().czyPusty() && czyWszystkieStanowiskaPuste(system.getMyjnie())) {
//				System.out.println("_____________System nie jest pusty");
				return true;
			}
//			System.out.println("__________________system jest pusty");
			return false;
		}		
			
			private boolean czyWszystkieStanowiskaPuste(List<Stanowisko<Samochod>> stanowiska) {
				for(Stanowisko<Samochod> stanowisko : stanowiska) {
					if(!stanowisko.czyPusty()) {
//						System.out.println("_____stanowisko nie jest puste");
						return false;
					}
				}
				System.out.println("_____________wszystkie stanowiska puste");
				return true;
			}
			
	public static void main(String[] args) {
		Network n = new Network();
		n.symulacja();
	}

}

class Generator {

}
